/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package wwcontrolserver;

//note the library location on the SBC has to be annoyingly added to the manifest file for unknown reasons
//import com.phidgets.*;
import wwcontrolserver.sensor.SensorContainer;
import wwcontrolserver.listeners.WWSensorListener;
import wwcontrolserver.listeners.WWDigitalOutputListener;
import wwcontrolserver.listeners.WWDetachListener;
import wwcontrolserver.listeners.WWAttachListener;
import wwcontrolserver.datarecorders.WWControlServerLogger;
import wwcontrolserver.datarecorders.WWDatabaseConnection;
import wwcontrolserver.sensor.SensorThermistor1134;
import wwcontrolserver.sensor.SensorPHORP_1130;
import wwcontrolserver.sensor.AbstractSensor;
//import com.phidgets.InterfaceKitPhidget;
import com.phidgets.Phidget;
import com.phidgets.PhidgetException;
//import java.io.BufferedWriter;
import java.io.File;
// java.io.FileWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
//import java.util.Date;
import java.util.HashMap;
//import java.util.Timer;
import java.util.Properties;
import org.tmatesoft.sqljet.core.SqlJetException;
import wwcontrolserver.controls.AbstractControl;
import wwcontrolserver.controls.ControlManager;
import wwcontrolserver.controls.DataCollectionControl;
import wwcontrolserver.controls.OnOffControlState;
import wwcontrolserver.controls.DigesterHeaterControl;
import wwcontrolserver.controls.DigesterMotorControl;
import wwcontrolserver.controls.DutyCycleControlState;
import wwcontrolserver.controls.SetPointHeaterControlState;
import wwcontrolserver.datarecorders.AbstractDataRecorder;
import wwcontrolserver.datarecorders.WWControlSensorLogFile;
import wwcontrolserver.ifk.AbstractIFK;
import wwcontrolserver.ifk.AnalogInputIFK;
import wwcontrolserver.ifk.DYNR;
import wwcontrolserver.ifk.DigitalOutputIFK;

//import org.tmatesoft.sqljet.core.SqlJetTransactionMode;
//import org.tmatesoft.sqljet.core.table.ISqlJetTable;
//import org.tmatesoft.sqljet.core.table.ISqlJetTransaction;
//import org.tmatesoft.sqljet.core.table.SqlJetDb;
//test
/**
 *
 * @author Michael Ferry
 */
public class WWControlServer {
    // private String OutputPath = "/home/qbisci";
    //Linux home output path
    //private String OutputPath = "/home/msferry/WWControlServerData";
    //Windows System Output
    //Desktop TestPath
    private final String fSep = System.getProperty("file.separator");
    private final String OutputPath = "C:/Users/Michael Ferry/programming/java/NetbeansProjects/ServerTestOutput";
    private final String PropertyFilePath = OutputPath + fSep + "WWCSProps.txt";
    private final Properties props = new Properties();
    //Laptop TestPath
    //private String OutputPath = "C:/Users/Michael Ferry/Documents/TestServerOutput";
    
    protected static final String FileDatePattern = ("MMddyyyy'_'HHmmss");
    protected SimpleDateFormat FileDateFormatter = new SimpleDateFormat(FileDatePattern);
    protected static final String LogEntryDatePattern = ("MM/dd/yyyy' 'HH:mm:ss");
    protected SimpleDateFormat LogEntryDateFormatter = new SimpleDateFormat(LogEntryDatePattern);
    protected WWControlServerLogger WWCSLog; 
    //public static final int NumberOfInterfaceKits=7;
    public static final int ifk_pHORP_serial = 48242;
    public static final int ifk_HeaterSensor_serial=106721;
    public static final int ifk_HeaterRelay_serial=266917;
    public static final int ifk_MotorRelay_serial=123785;
    public static final int ifk_P1_2_serial=178585;
    public static final int ifk_P3_serial=174418;
    public static final int ifk_P4_serial=145087;
    //public static final int ifk_P3_4_serial=145087;
    
//    public static final int ifk_pHORP_index=0;
//    public static final int ifk_HeaterSensor=1;
//    public static final int ifk_HeaterRelay=2;
//    public static final int ifk_MotorRelay=3;
//    public static final int ifk_P1_2=4;
//    public static final int ifk_P3=5;
//    public static final int ifk_P4=6;
    //public static final int ifk_P3_4=5;
    
    //public static final int[] ifkSerials = {48242,106721,266917,123785,178585,145087};
    //public static final int[] ifkSerials = {48242,106721,266917,123785,178585,174418,145087};
    
    //Calibration Groups - used to identify sensors which must be removed from service together upon calibration
    //This is usually due to their being attached to the same box or other structure
    //which must be removed for calibration
    //public static final int CALGROUP_INDPENDENT = 0;
    public static final int CALGROUP_INDEPENDENT = 0;
    public static final int CALGROUP_P3 = 1;
    public static final int CALGROUP_P4 = 2;
    
    public static final int P3_pH_SNUM = 1;
    public static final int P3_ORP_SNUM = 0;
    public static final int P4_pH_SNUM = 0;
    public static final int P4_ORP_SNUM = 1;
    public static final int P4_Temp_SNUM = 2;
    public static final double P4_Temp1134Setting = 8450;
    public static final int P4_TempThermistorRes25 = 10000;
    
    public static final double Dig_Temp1134Setting = 2610;
    public static final int Dig_TempThermistorRes25 =  2252; 
    public static final int Dig1Temp_SNUM=0;
    public static final int Dig2Temp_SNUM=1;
    public static final int Dig3Temp_SNUM=2;
    public static final int Dig4Temp_SNUM=4;
    
//    ifks_Name[ifk_pHORP_index] = "pHORP";
//        ifks_Name[ifk_HeaterSensor] = "HeaterSensor";
//        ifks_Name[ifk_HeaterRelay] = "HeaterRelay";
//        ifks_Name[ifk_MotorRelay] = "MotorRelay";
//        ifks_Name[ifk_P1_2] = "Pond1_2Sensor";
//        ifks_Name[ifk_P3] = "Pond3_Sensor";
//        ifks_Name[ifk_P4] = "Pond4_Sensor";
    
//    public final AbstractIFK [] WWCS_IFK; = {
//        new AnalogInputIFK(WWCSLog, ifk_pHORP_serial, "DigesterPHORP",AnalogInputIFK.TWELVEBIT_DYNR),
//        new AnalogInputIFK(WWCSLog, ifk_HeaterSensor_serial, "DigesterHeaterSensor",AnalogInputIFK.TWELVEBIT_DYNR),
//        new DigitalOutputIFK(WWCSLog, ifk_HeaterRelay_serial, "DigesterHeaterRelay"),
//        new DigitalOutputIFK(WWCSLog, ifk_MotorRelay_serial, "MotorRelay"),
//        new AnalogInputIFK(WWCSLog, ifk_P1_2_serial, "Pond1_2_Analog",AnalogInputIFK.TWELVEBIT_DYNR),
//        new AnalogInputIFK(WWCSLog, ifk_P3_serial, "Pond3_Analog",AnalogInputIFK.TWELVEBIT_DYNR),
//        new AnalogInputIFK(WWCSLog, ifk_P4_serial, "Pond4_Analog",AnalogInputIFK.TWELVEBIT_DYNR)
//    };
    private final HashMap<Integer,AbstractIFK> IFKmap = new HashMap<Integer,AbstractIFK>();
    private ArrayList<AbstractIFK> IFKarray;
    
    
    public static final AbstractSensor [] WWCS_Sensors = {
        new SensorPHORP_1130(ifk_P3_serial, P3_pH_SNUM,CALGROUP_P3, "P3 pH",SensorPHORP_1130.PHMODE_1130),
        new SensorPHORP_1130(ifk_P3_serial, P3_ORP_SNUM,CALGROUP_P3, "P3 ORP",SensorPHORP_1130.ORPMODE_1130),
        new SensorPHORP_1130(ifk_P4_serial, P4_pH_SNUM,CALGROUP_P4, "P4 pH",SensorPHORP_1130.PHMODE_1130),
        new SensorPHORP_1130(ifk_P4_serial, P4_ORP_SNUM,CALGROUP_P4, "P4 ORP",SensorPHORP_1130.ORPMODE_1130),
        new SensorThermistor1134(ifk_P4_serial, P4_Temp_SNUM,CALGROUP_P4, "P4 ORP",P4_Temp1134Setting,P4_TempThermistorRes25),
        new SensorThermistor1134(ifk_HeaterSensor_serial,Dig1Temp_SNUM,CALGROUP_INDEPENDENT,"Dig1 Temp",Dig_Temp1134Setting,Dig_TempThermistorRes25),
        new SensorThermistor1134(ifk_HeaterSensor_serial,Dig2Temp_SNUM,CALGROUP_INDEPENDENT,"Dig2 Temp",Dig_Temp1134Setting,Dig_TempThermistorRes25),
        new SensorThermistor1134(ifk_HeaterSensor_serial,Dig3Temp_SNUM,CALGROUP_INDEPENDENT,"Dig3 Temp",Dig_Temp1134Setting,Dig_TempThermistorRes25),
        new SensorThermistor1134(ifk_HeaterSensor_serial,Dig4Temp_SNUM,CALGROUP_INDEPENDENT,"Dig4 Temp",Dig_Temp1134Setting,Dig_TempThermistorRes25),
    };
    
//    public static final AbstractSensor [] WWCS_KeyValues = {new AbstractSensor(ifk_P3_serial, P3_pH_SNUM,CALGROUP_P3, "P3 pH"),
//        new AbstractSensor(ifk_P3_serial, P3_ORP_SNUM,CALGROUP_P3, "P3 ORP"),
//        new AbstractSensor(ifk_P4_serial, P4_pH_SNUM,CALGROUP_P4, "P4 pH"),
//        new AbstractSensor(ifk_P4_serial, P4_ORP_SNUM,CALGROUP_P4, "P4 ORP"),
//        new AbstractSensor(ifk_P4_serial, P4_Temp_SNUM,CALGROUP_P4, "P4 Temp")};
        

    
//    //SensorKeys
//    public static final SensorKey [] WWCSKeys = {new SensorKey(ifk_P3_serial, P3_pH_SNUM),
//        new SensorKey(ifk_P3_serial, P3_ORP_SNUM),new SensorKey(ifk_P4_serial, P4_pH_SNUM),
//        new SensorKey(ifk_P4_serial, P4_ORP_SNUM),new SensorKey(ifk_P4_serial, P4_Temp_SNUM)};
//    //SensorValues
//    public static final SensorValue [] WWCSValues = {new SensorValue(CALGROUP_P3, "P3 pH"),
//        new SensorValue(CALGROUP_P3, "P3 ORP"),new SensorValue(CALGROUP_P4, "P4 pH"),
//        new SensorValue(CALGROUP_P4, "P4 ORP"),new SensorValue(CALGROUP_P4, "P4 Temp")};
    
   
//    //sensor mappings, Key: IFK,SensorNumber  Value: CALGROUP,Name
//    public static final SensorKey P3_pH_KEY = new SensorKey(ifk_P3_serial, 1);
//    public static final SensorValue P3_pH_VALUE = new SensorValue(CALGROUP_P3, "P3 pH");
//    public static final SensorKey P3_ORP_KEY = new SensorKey(ifk_P3_serial, 0);
//    public static final SensorValue P3_ORP_VALUE = new SensorValue(CALGROUP_P3, "P3 ORP");
//    public static final SensorKey P4_pH_KEY = new SensorKey(ifk_P4_serial, 0);
//    public static final SensorValue P4_pH_VALUE = new SensorValue(CALGROUP_P4, "P4 pH");
//    public static final SensorKey P4_ORP_KEY = new SensorKey(ifk_P4_serial, 1);
//    public static final SensorValue P4_ORP_VALUE = new SensorValue(CALGROUP_P4, "P4 ORP");
//    public static final SensorKey P4_Temp_KEY = new SensorKey(ifk_P4_serial, 2);
//    public static final SensorValue P4_Temp_VALUE = new SensorValue(CALGROUP_P4, "P4 Temp");
    //Make sure that if new SensorKey, Sensor Value pairs are added that they are also added to
    //the comparator
    public static final SensorContainer SContainer = new SensorContainer(WWControlServer.WWCS_Sensors);
    public final ArrayList<AbstractControl> ListOfControls = new ArrayList<AbstractControl>();
    public ControlManager CManager = null;

   // public static final double PhidgetsRawSensorDynRange=4.096;
    //public static final double PhidgetsRawSensorDynRange=1;
    
    //BufferedWriter for the log writer
    //private BufferedWriter LogWriter;
   
    
//    public static final int MIN_TO_MILLSEC = 60000;
//    public static final int ControlInterval = 1000;
    
    //Sensor trigger and dynamic range;
    //public static final int LOW_TRIGGER = 3;
    //public static final double TENBIT_DYNR = 1.0;
    //public static final double TWELVEBIT_DYNR = 4.096;

    
    //public static final String[] ifks_Name = new String[NumberOfInterfaceKits];   
    //protected InterfaceKitPhidget[] ifks = new InterfaceKitPhidget[NumberOfInterfaceKits];
    //Determines the default state for the Ratiometric state of each interface kit;
//    public static final boolean DefaultRatiometric_pHORP = false;
//    public static final boolean DefaultRatiometric_HeaterSensor = true;
//    public static final boolean DefaultRatiometric_P1_2 = false;
//    public static final boolean DefaultRatiometric_P3 = false;
//    public static final boolean DefaultRatiometric_P4 = false;
      
    //DATA COLLECTION VARIABLES
    //private Timer DataTimer = null;
    //private DataCollectionTaskServer dTask = null;
    //private long DataCollectionIntervalMilliSeconds = 60000;
   
    protected static final String DB_NAME = "PhidgetsData_07122012.sqlite";
//    protected static final String SENSOR_TABLE_NAME = "sensor";
//    protected static final String DO_TABLE_NAME = "DO";
//    protected static final String DI_TABLE_NAME = "DI";
//    protected static final String ATTACH_LOG_TABLE_NAME = "Attach_Log";
//    protected SqlJetDb OutputDatabase;
//    protected ISqlJetTable SensorTable;
//    protected ISqlJetTable DOTable;
//    protected ISqlJetTable DITable;
//    protected ISqlJetTable AttachTable;
    private final ArrayList<AbstractDataRecorder> WWCS_DataRecorders = new ArrayList<AbstractDataRecorder>();
   // protected WWDatabaseConnection WWDB = null;
    //protected boolean InputSensorChangeDB = false;
    //DATA COLLECTION VARIABLES
       
    //HEATER CONTROL VARIABLES
//    public static final double DefaultTempSetPoint = 34.5;
//    public static final double DefaultTempSetRange = 0.5;        
//    protected double[] TempSetPoint = {DefaultTempSetPoint,DefaultTempSetPoint,DefaultTempSetPoint,DefaultTempSetPoint};
//    protected double[] TempSetRange = {DefaultTempSetRange,DefaultTempSetRange,DefaultTempSetRange,DefaultTempSetRange};
//    public static final int[] HeaterSensorMap = {0,1,2,3};
//    public static final int[] HeaterSensorToRelayMap = {0,1,2,3};
//    protected boolean[] HeaterControlState = {true,true,true,true};
    //HEATER CONTROL VARIABLES
    
    //MOTOR CONTROL VARIABLES
   // private Timer MotorTimer = null;
   // private MotorControlTaskServer mTask = null;
    //Minutes that the motor is running during a cycle
    //private long DC1_MotorRunDurationMilli=15*MIN_TO_MILLSEC;
    //Total cycle time in minutes
  //  private long DC1_MotorPeriodMilli=60*MIN_TO_MILLSEC;
    //private double MotorDutyCycle;
   // public static final int DCMotorDO=3;
    //global state for the motor being on or off
    //protected boolean DCMotorState = false;
    //MOTOR CONTROL VARIABLES
    
    //Control Information
    public static final int Dig1CID = 1000;
    public static final int Dig1SNUM = 0;
    public static final int Dig1RNUM = 0;
    public static final int Dig2CID = 1001;
    public static final int Dig2SNUM = 1;
    public static final int Dig2RNUM = 1;
    public static final int Dig3CID = 1002;
    public static final int Dig3SNUM = 2;
    public static final int Dig3RNUM = 2;
    public static final int Dig4CID = 1003;
    public static final int Dig4SNUM = 3;
    public static final int Dig4RNUM = 3;
    public static final int DigMotorCID = 1004;
    public static final int DigMotorRNUM = 3;
    public static final int DataCollectionCID = 1005;

    //Listeners
    WWAttachListener WWAL;
    WWDetachListener WWDL;
    WWSensorListener WWSL;
    WWDigitalOutputListener WWOL;
    
    //Calibration Info
    //public static final String [] CalGroups = {"Pond 3","Pond 4"};
    //public static final String [][] CalGroupP3Fields = {{"P3 pH"},{"P3 ORP"}};
    //public static final String [][] CalFields = {{"P3 pH"},{"P3 ORP"},{"P4 pH"},{"P4 ORP"},{"P4 Temp"}};
    //public static final int CALGROUP_P3 = 0;
    //public static final int CALGROUP_P4 = 1;
    //public static final int [][] CalMap = {{ifk_P3_serial,1,CALGROUP1},{ifk_P3_serial,0,CALGROUP1},
       // {ifk_P4_serial,0,CALGROUP2},{ifk_P4_serial,1,CALGROUP2},{ifk_P4_serial,2,CALGROUP2}};
    
    /////////////////////////////////////////////////////////////////////////////
    /////////////       SERVER SETUP VARIABLES      ////////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    private ServerSocket ServerSocketToListen;
    private boolean listening = true;
    public static final int ListenPort = 4444;
    //private WWControlServerState WWCSState;
    ////////////////////////////////////////////////////////////////////////////
    
    /**
     * @param args the command line arguments
     */
    
    @SuppressWarnings("empty-statement")
    public WWControlServer() {
        
        try {
            FileInputStream fileInput = new FileInputStream(PropertyFilePath);
            props.load(fileInput);
            fileInput.close();
        } catch (IOException e) {
           System.out.println(e.toString());
        }

        WWCSLog = new WWControlServerLogger(OutputPath + fSep, FileDateFormatter, LogEntryDateFormatter,
                props.getProperty("RecipientEmail"),props.getProperty("SenderGmailUname"),props.getProperty("SenderGmailPass"));
        //Setup the server log file
        
//        try {
//            Date currTime = new Date();
//            
            //String ServerLogFilePath = OutputPath + fSep + FileDateFormatter.format(currTime) + "_ServerLogFile.txt";
           
           
//            System.out.println("Server log file path: " + ServerLogFilePath);
//            LogWriter = new BufferedWriter(new FileWriter(ServerLogFilePath));
//            RecordLogEntry("Server started");           
//        } catch (IOException e) {
//            System.out.println(e);
//        }
        
        File dbFile = new File(OutputPath + fSep + DB_NAME);
        //System.out.println("Database file exists? " + dbFile.exists());
        WWCSLog.RecordLogEntry("Database file exists? " + dbFile.exists());
//        try {
//            WWDB = new WWDatabaseConnection(WWCSLog,dbFile);
//        } catch (SqlJetException sqle) {
//            System.out.println(sqle);           
//            WWCSLog.RecordLogEntry(sqle.toString());
//        }
        
        //Setup the Data Recorders
        try {
            WWCS_DataRecorders.add(new WWDatabaseConnection(WWCSLog, dbFile));
        } catch (SqlJetException sqle) {
            System.out.println(sqle);
            WWCSLog.RecordLogEntry(sqle.toString());

        }
        WWCS_DataRecorders.add(new WWControlSensorLogFile(OutputPath + fSep, FileDateFormatter, LogEntryDateFormatter));

        WWAL = new WWAttachListener(WWCSLog,WWCS_DataRecorders,IFKmap,CManager);
        WWDL = new WWDetachListener(WWCSLog,WWCS_DataRecorders,IFKmap,CManager);
        //WWSL = new WWSensorListener(this,WWDB);
        WWOL = new WWDigitalOutputListener(WWCSLog,WWCS_DataRecorders);
        //WWCS_IFK = 
        //initComponents();
        //Setup IFK hashmap
        try {
            
            
            IFKmap.put(ifk_pHORP_serial, new AnalogInputIFK(ifk_pHORP_serial, "DigesterPHORP",SContainer, WWAL, WWDL, DYNR.TWELVEBIT));
            IFKmap.put(ifk_HeaterSensor_serial, new AnalogInputIFK(ifk_HeaterSensor_serial, "DigesterHeaterSensor",SContainer, WWAL, WWDL, DYNR.TWELVEBIT));
            IFKmap.put(ifk_HeaterRelay_serial, new DigitalOutputIFK(ifk_HeaterRelay_serial, "DigesterHeaterRelay", WWAL, WWDL));
            IFKmap.put(ifk_MotorRelay_serial, new DigitalOutputIFK(ifk_MotorRelay_serial, "MotorRelay", WWAL, WWDL));
            IFKmap.put(ifk_P1_2_serial, new AnalogInputIFK(ifk_P1_2_serial, "Pond1_2_Analog",SContainer, WWAL, WWDL, DYNR.TWELVEBIT));
            IFKmap.put(ifk_P3_serial, new AnalogInputIFK(ifk_P3_serial, "Pond3_Analog",SContainer, WWAL, WWDL, DYNR.TWELVEBIT));
            IFKmap.put(ifk_P4_serial, new AnalogInputIFK(ifk_P4_serial, "Pond4_Analog",SContainer, WWAL, WWDL, DYNR.TWELVEBIT));
            //Open desired IFK's
            
            //ifks[ifk_HeaterSensor].addSensorChangeListener(WWSL);
            

            IFKmap.get(ifk_HeaterRelay_serial).AddOutputChangeListener(WWOL);
            IFKmap.get(ifk_MotorRelay_serial).AddOutputChangeListener(WWOL);
            //if(IFma)
            IFKarray = new ArrayList<AbstractIFK>(IFKmap.values());
            

            ListOfControls.add(new DigesterHeaterControl(
                    new SetPointHeaterControlState(Dig1CID, "Digester1 Control",
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_POINT,
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_RANGE,
                        SetPointHeaterControlState.DEFAULT_CONTROL_STATE),
                    WWCSLog,
                    (AnalogInputIFK) IFKmap.get(ifk_HeaterSensor_serial), Dig1SNUM,
                    (DigitalOutputIFK) IFKmap.get(ifk_HeaterRelay_serial), Dig1RNUM));
            
            
            
            ListOfControls.add(new DigesterHeaterControl(
                    new SetPointHeaterControlState(Dig2CID, "Digester2 Control",
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_POINT,
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_RANGE,
                        SetPointHeaterControlState.DEFAULT_CONTROL_STATE),
                    WWCSLog,
                    (AnalogInputIFK) IFKmap.get(ifk_HeaterSensor_serial), Dig2SNUM,
                    (DigitalOutputIFK) IFKmap.get(ifk_HeaterRelay_serial), Dig2RNUM));
            

            
            ListOfControls.add(new DigesterHeaterControl(
                    new SetPointHeaterControlState(Dig3CID, "Digester3 Control",
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_POINT,
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_RANGE,
                        SetPointHeaterControlState.DEFAULT_CONTROL_STATE),
                    WWCSLog,
                    (AnalogInputIFK) IFKmap.get(ifk_HeaterSensor_serial), Dig3SNUM,
                    (DigitalOutputIFK) IFKmap.get(ifk_HeaterRelay_serial), Dig3RNUM));
            
   
            
            ListOfControls.add(new DigesterHeaterControl(
                    new SetPointHeaterControlState(Dig4CID, "Digester4 Control",
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_POINT,
                        SetPointHeaterControlState.DEFAULT_DIGESTER_TEMP_SET_RANGE,
                        SetPointHeaterControlState.DEFAULT_CONTROL_STATE),
                    WWCSLog,
                    (AnalogInputIFK) IFKmap.get(ifk_HeaterSensor_serial), Dig4SNUM,
                    (DigitalOutputIFK) IFKmap.get(ifk_HeaterRelay_serial), Dig4RNUM));
                                            

            
            ListOfControls.add(new DigesterMotorControl(
                    new DutyCycleControlState(DigMotorCID, "Digester Motor"),
                    WWCSLog,
                    (DigitalOutputIFK) IFKmap.get(ifk_MotorRelay_serial), DigMotorRNUM));
            
 
            ListOfControls.add(new DataCollectionControl(
                    new OnOffControlState(DataCollectionCID,"DataCollection Control",
                            OnOffControlState.DEFAULT_CONTROL_STATE),
                    WWCSLog,WWCS_DataRecorders,IFKarray));
                    
           

            IFKmap.get(ifk_HeaterSensor_serial).open();
            IFKmap.get(ifk_HeaterRelay_serial).open();
            IFKmap.get(ifk_MotorRelay_serial).open();
            IFKmap.get(ifk_P3_serial).open();
            IFKmap.get(ifk_P4_serial).open();
            try {
                CManager = new ControlManager(ListOfControls, WWCSLog);
            } catch (Exception e) {
                WWCSLog.RecordExceptionLogEntry(e);
            }

            WWCSLog.RecordLogEntry(Phidget.getLibraryVersion());
                       
        } catch (PhidgetException Phe) {
            WWCSLog.RecordExceptionLogEntry(Phe);
        }
        
//        = {
//        new AnalogInputIFK(WWCSLog, ifk_pHORP_serial, "DigesterPHORP",AnalogInputIFK.TWELVEBIT_DYNR),
//        new AnalogInputIFK(WWCSLog, ifk_HeaterSensor_serial, "DigesterHeaterSensor",AnalogInputIFK.TWELVEBIT_DYNR),
//        new DigitalOutputIFK(WWCSLog, ifk_HeaterRelay_serial, "DigesterHeaterRelay"),
//        new DigitalOutputIFK(WWCSLog, ifk_MotorRelay_serial, "MotorRelay"),
//        new AnalogInputIFK(WWCSLog, ifk_P1_2_serial, "Pond1_2_Analog",AnalogInputIFK.TWELVEBIT_DYNR),
//        new AnalogInputIFK(WWCSLog, ifk_P3_serial, "Pond3_Analog",AnalogInputIFK.TWELVEBIT_DYNR),
//        new AnalogInputIFK(WWCSLog, ifk_P4_serial, "Pond4_Analog",AnalogInputIFK.TWELVEBIT_DYNR)       
        //System.out.println(Phidget.getLibraryVersion());
       
        //SetupInterfaceKits();
        //StartWWControlServer();
        
    }
    
    public void StartWWControlServer() {
        try {
            
            ServerSocketToListen = new ServerSocket(ListenPort);
            String OutMessage = "Server started on port: " + ListenPort;
            System.out.println(OutMessage);
            WWCSLog.RecordLogEntry(OutMessage);
        } catch (IOException e) {
            String OutMessage = "Could not listen on port: " + ListenPort;
            WWCSLog.RecordExceptionLogEntry(e);
            System.exit(-1);
        }
        try {
            while (listening) {
                new WWControlServerMultiThread(this,ServerSocketToListen.accept()).start();
            }
            ServerSocketToListen.close();
        } catch (IOException e) {
             WWCSLog.RecordExceptionLogEntry(e);
        }
    }
    
    public WWControlServerState GetServerState() {

        ArrayList<Boolean> ifksAttached = new ArrayList<Boolean>();
        try {
            for (AbstractIFK IFKtoProcess : IFKarray) {
                ifksAttached.add(IFKtoProcess.isAttached());
            }
        } catch (PhidgetException phe) {
             WWCSLog.RecordExceptionLogEntry(phe);
        }

        WWControlServerState WWCSState = new WWControlServerState(CManager.GetStateOfAllControls(),ifksAttached);   
        WWCSState.MessageFlag = WWControlServerState.StateFlags.SERVER_STATUS;
        
        return WWCSState;

    }

    protected void Exit() {
        CManager.ShutdownControlManager();


        try {
            for (AbstractIFK ifkToProcess : IFKarray) {
                ifkToProcess.close();
            }
        } catch (PhidgetException phe) {
            WWCSLog.RecordExceptionLogEntry(phe);
        }
        for (AbstractDataRecorder DataRecorderToProcess : WWCS_DataRecorders) {
            DataRecorderToProcess.close();
        }

        //Try to shutdown log writer         
        WWCSLog.close();

        System.out.println("WWControlServer shutting down...");
        System.exit(0);
    }

    
    /////////////////////////////////////////////////////////////////////////////////////////////////
    // Initial Setup of the Interface Kits
    /////////////////////////////////////////////////////////////////////////////////////////////////
//    private void SetupInterfaceKits() {
//        try {
////////////////////////////////////////////////////////////////////////////////////////////////////////
//            //Setup the pHandORP Phidgets Interface Kit
//            for (int i = 0; i < ifks.length; i++) {
//                ifks[i] = new InterfaceKitPhidget();
//                ifks[i].addAttachListener(WWAL);
//                ifks[i].addDetachListener(WWDL);
//            }
//            ifks[ifk_HeaterSensor].addSensorChangeListener(WWSL);
//            
//            ifks[ifk_HeaterRelay].addOutputChangeListener(WWOL);
//            ifks[ifk_MotorRelay].addOutputChangeListener(WWOL);
//            
//            
// //////////////////////////////////////////////////////////////////////////////////////////////////
//        //end setup of ifk's
// /////////////////////////////////////////////////////////////////////////////////////////////////
//        
//            //ifks[ifk_pHORP_index].open(ifk_pHORP_serial);
//            ifks[ifk_HeaterSensor].open(ifk_HeaterSensor_serial);
//            ifks[ifk_HeaterRelay].open(ifk_HeaterRelay_serial);
//            ifks[ifk_MotorRelay].open(ifk_MotorRelay_serial);
//            //ifks[ifk_P1_2].open(ifk_P1_2_serial);
//            ifks[ifk_P3].open(ifk_P3_serial);
//            ifks[ifk_P4].open(ifk_P4_serial);
//
//           
//
//        } catch(PhidgetException ex){
//            String OutMessage = ex.getDescription()+ "Phidget Error" + ex.getErrorNumber();
//            System.out.println(OutMessage);
//            WWCSLog.RecordLogEntry(OutMessage);
//            
//            //JOptionPane.showMessageDialog(this, ex.getDescription(), "Phidget Error" + ex.getErrorNumber(), JOptionPane.ERROR_MESSAGE);
//            //dispose();
//            //System.exit(0);
//        };
//    }
    /**
     * @param args the command line arguments
     */
   
    
    public static void main(String[] args)  {
        // TODO code application logic here
        //System.out.println("Hello World!");
        WWControlServer s1 = new WWControlServer();
        s1.StartWWControlServer();
        //while(true);
        
    }
}
